package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.article.entity.ApArticle;
import com.heima.common.dto.PageResponseResult;
import com.heima.common.dto.ResponseResult;
import com.heima.common.dto.User;
import com.heima.common.util.UserThreadLocalUtil;
import com.heima.search.dto.ApArticleSearchDto;
import com.heima.search.entity.ApArticleDoc;
import com.heima.search.service.IApUserSearchService;
import com.heima.search.service.IArticleSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author: itheima
 * @create: 2022-08-09 10:30
 */
@Slf4j
@Service
public class ArticleSearchServiceImpl implements IArticleSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private IApUserSearchService apUserSearchService;



    /**
     * 关键字模糊检索文章列表
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(ApArticleSearchDto dto) {
        try {
            //1.构建搜索请求对象SearchRequest 封装查询索引库
            SearchRequest searchRequest = new SearchRequest("app_info_article");

            //2.构建请求参数对象SearchSourceBuilder 封装请求体body参数 查询方式、分页、排序、过滤字段、高亮、聚合、算分函数
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            //2.1 设置请求参数中查询方式 query部分 bool查询-多条件组合查询
            sourceBuilder.query(basicQuery(dto));
            //2.2 设置分页 from size
            Long from = (dto.getPage() - 1) * dto.getSize();
            Integer size = dto.getSize();
            sourceBuilder.from(from.intValue());
            sourceBuilder.size(size);

            //2.3 设置排序 sort
            sourceBuilder.sort("publishTime", SortOrder.DESC);

            //2.4 设置过滤字段
            sourceBuilder.fetchSource(null, new String[]{"isDown", "isDelete"});

            //2.5 设置高亮 TODO 自己完成
            //sourceBuilder.highlighter();

            //3.将SearchSourceBuilder添加到SearchRequest中
            searchRequest.source(sourceBuilder);

            //4.执行检索
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //6.TODO 存储用户搜索历史
            User user = UserThreadLocalUtil.get();
            apUserSearchService.save(dto, user.getUserId());

            //5.封装响应数据-业务数据
            return handlerResponseData(searchResponse, dto);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("检索异常,{}", e);
            return null;
        }
    }


    /**
     * 构建请求参数中query部分查询方式设置
     *
     * @param dto 查询条件
     * @return
     */
    private QueryBuilder basicQuery(ApArticleSearchDto dto) {
        //1.构建bool查询对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //2.根据关键字查询all字段
        if (StringUtils.isNotBlank(dto.getSearchWords())) {
            MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("all", dto.getSearchWords()).operator(Operator.AND);
            boolQuery.must(matchQuery);
        } else {
            MatchAllQueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
            boolQuery.must(matchAllQuery);
        }

        //3.过滤条件 isDelete isDown
        boolQuery.filter(QueryBuilders.termQuery("isDown", false));
        boolQuery.filter(QueryBuilders.termQuery("isDelete", false));
        return boolQuery;
    }


    /**
     * 处理检索后后业务数据
     *
     * @param searchResponse
     * @param dto
     * @return 分页结果对象
     */
    private ResponseResult handlerResponseData(SearchResponse searchResponse, ApArticleSearchDto dto) {
        //1.获取命中总记录数
        long total = searchResponse.getHits().getTotalHits().value;
        //2.获取命中业务数据
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<ApArticleDoc> list = new ArrayList<>();
        if (hits != null && hits.length > 0) {
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                ApArticleDoc apArticleDoc = JSON.parseObject(sourceAsString, ApArticleDoc.class);
                list.add(apArticleDoc);
            }
        }
        return new PageResponseResult(dto.getPage(), dto.getSize(), total, list);
    }
}
